#!/usr/bin/env perl

# use strict;
use warnings;

BEGIN {
	push @INC,$ENV{CODEMGR_LIBS} if exists($ENV{CODEMGR_LIBS});
}


use Getopt::Long;
use File::Basename;
use File::Find;
use File::Spec;
use Config;
use Cwd;
use codemgr2 qw(logmsg warnmsg errormsg parse_rlogs load_config globfiles
		get_project attempt_alias_map break_into_dirs);
eval "use pv3;";
if($@) {
	errormsg("Unable to open PV3 utility library.",1);
}

$ARG_project=undef;
$ARG_sqlfile=undef;
$ARG_sqlite3=undef;
$ARG_verbose=0;

sub usage {
	$_PRG=basename($0);
	$_SPC=" " x length($_PRG);
	print "
Usage: $_PRG [--project P] [--sqlfile F] [--sqlite3 S] [--verbose]

The $_PRG utility takes the output of the 'cm2 dump sql' command
and performs the import of this data (via the sqlite3 utility).

The aim is to provide an import facility to upgrade from sqlite2
version PV3 repository or to re-generate the database to 
allow space optimisation.

Written by Simon Edwards (C) 2009-2010, advantsys.co.uk
For more information see the $_PRG(1) manual page.
";
	exit(1);
}

if(!exists($ENV{PROJECTS_ROOT})) {
	errormsg("Required environment variable \"PROJECTS_ROOT\" is not set.",3);
}

if(! -d $ENV{PROJECTS_ROOT}) {
	errormsg("\"PROJECTS_ROOT\" directory \"$PROJECTS_ROOT\" does not exist.",2);
}
$PROJECTS_ROOT=$ENV{PROJECTS_ROOT};

if(!GetOptions(
	"project=s"	=> \$ARG_project,
	"sqlfile=s"	=> \$ARG_sqlfile,
	"sqlite3=s"	=> \$ARG_sqlite3,
	"verbose"	=> \$ARG_verbose,
)) {
	usage();
}

if(!defined($ARG_sqlfile)) {
	$ARG_sqlfile="-";
}

if(!defined($ARG_sqlite3)) {
	my @P=File::Spec->path();
	for my $cd (@P) {
		if(-x "$cd/sqlite3") {
			$ARG_sqlite3="$cd/sqlite3"; last;
		}
	}
} else {
	if(! -x $ARG_sqlite3) {
		errormsg("The --sqlite3 option specified does not exist, or is not executable.",1);
	}
}
if(!defined($ARG_sqlite3)) {
	errormsg("No --sqlite3 flag and sqlite3 utility not found in PATH.",1);
}

logmsg("SQLite3 utility: $ARG_sqlite3");

if(!defined($ARG_project)) {
	if(!exists($ENV{CM2_REALPATH}) || $ENV{CM2_REALPATH}==0) {
		@r=get_project(getcwd,undef);
	} else {
		@r=get_project($ENV{PWD},undef);
	}
	if(defined($r[0])) {
		$ARG_project=$r[0];
	} else {
		if($r[1]==1) {
			errormsg("No project owning this directory has been found!",1);
		}
		if($r[1]==2) {
			errormsg("Multiple projects owning this directory have been found!",1);
		}
		errormsg($r[2],2);
		exit 1;
	}
} else {
	#################################################################
	# Work out the project based on ARG_project when might simply	#
	# be an alias rather than the real project name...		#
	#################################################################
	if(! -d "$PROJECTS_ROOT/$ARG_project") {
		$alias=$ARG_project;
		$realname=attempt_alias_map($ARG_project);
		if(defined($realname)) {
			$ARG_project=$realname;
			logmsg("Matched project \"$realname\" via alias \"$alias\".");
		} else {
			errormsg("Project source directory \"$ARG_project\" does not exist.",2);
		}
	}
}

my $config=load_config("$PROJECTS_ROOT/$ARG_project/.meta");
if(exists($config->{REPOS_TYPE})) {
	$repos_type=$config->{REPOS_TYPE}->[0];
} else {
	errormsg("Missing REPOS_TYPE definition for repository!",1);
}
if($repos_type!=3) {
	errormsg("The project in question is using a V$repos_type repository rather than a V3 one.",1);
}

if($ARG_sqlfile ne "-") {
	if(! -e $ARG_sqlfile) {
		errormsg("Specified SQL Dump file does not exist.",1);
	}
	if(! -f $ARG_sqlfile) {
		errormsg("Specified SQL Dump file is not a regular file.",1);
	}
	if(! -r $ARG_sqlfile) {
		errormsg("Specified SQL Dump file is not readable.",1);
	}
}

my $fdd;
open($fdd,$ARG_sqlfile) or 
	errormsg("Unable to open SQL Dump file for reading: $!",1);

my $firstline=1;
my @D=();
my $sd=undef;
my @generated=();
while(my $cline=<$fdd>) {
	chomp $cline;
	if($firstline) {
		$firstline=0;
		if($cline !~ /^\%\%PROJECT_NAME\%\%/) {
			errormsg("File specified does not appear to be in expected format.",1);
		}
		next;
	}
	if($cline =~ /^\%\%DATA_SOURCE_DIR\%\%\s+(.*)/) {
		if(defined($sd)) {
			my $rr=install_data($sd,\@D);
			if($rr) {
				push @generated,$sd;
			} else {
				abort_install(\@generated);
			}
		}
		$sd=$1;
		@D=();
	} else {
		push @D,$cline;
	}
}
close($fdd);
if(defined($sd)) {
	my $rr=install_data($sd,\@D);
	if($rr) {
		push @generated,$sd;
	} else {
		abort_install(\@generated);
	}
}

# Now all the files will have been written to _PV3,pv3 in the directories
# in question, so we just do a rename now...

my $PR="$PROJECTS_ROOT/$ARG_project";
for my $xx (@generated) {
	if(!rename("$PR/$xx/_PV3,pv3","$PR/$xx/PV3,pv3")) {
		errormsg("Unable to rename _PV3,pv3 to PV3,pv3 in '$PR/$xx': $!",1);
	}
}
exit(0);

sub install_data {
my $dir=shift;
my $ref=shift;

	logmsg("Restoring data for directory '$dir'.");
	if(-f "$PROJECTS_ROOT/$ARG_project/$dir/_PV3,pv3") {
		unlink("$PROJECTS_ROOT/$ARG_project/$dir/_PV3,pv3");
	}
	if(! -d "$PROJECTS_ROOT/$ARG_project/$dir") {
		mkdir "$PROJECTS_ROOT/$ARG_project/$dir";
	}
	open($fd,"|$ARG_sqlite3 $PROJECTS_ROOT/$ARG_project/$dir/_PV3,pv3") 
		or return(0);

	for my $cline (@$ref) {
		if(! print $fd "$cline\n") {
			return(0);
		}
	}
	close($fd);
	return(1);
}

sub abort_install {
my $ref=shift;

	for my $cdir (@$ref) {
		if(-f "$PROJECTS_ROOT/$ARG_project/$dir/_PV3,pv3") {
			unlink("$PROJECTS_ROOT/$ARG_project/$dir/_PV3,pv3");
		}
	}
	exit(1);
}

